package com.common.util.javers.process;

import com.common.util.javers.UseEntityI18N;
import com.common.util.javers.UseValueI18N;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.log4j.Log4j;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;
import org.javers.core.diff.Change;
import org.javers.core.diff.changetype.ValueChange;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

/**
 * @author lankanqi
 * 字段过滤方式 (有优先级  1>2>3) 所以第一个的是最早过滤的
 * 1.在class 的字段上加  diffingnore注解 一般为实体类
 * 2.在propertyFiler加上需要过滤的      一般为公共字段 比如 hashcode等
 * 3.不对该字段做国际化处理
 * @since 2015-11-17
 * @implNote logging
 */
@Getter
@Setter
@Log4j
public abstract class AbstractLogProcessor implements LogProcess{

    protected List<String> propertyFilter;

    protected I18NProcess i18NProcess;

    @Override
    public void doLog(String moduleName, Serializable identityId, String operationName) {
        addLogForUpdate(moduleName,identityId,operationName,"");
    }

    @Override
    public void doLog(String moduleName, Serializable identityId, String operationName, Object object, List<Change> changes) {
        try {
            String changStr=resolveChangeList(object, changes);
            addLogForUpdate( moduleName, identityId, operationName,changStr);
        }catch (Exception e){
            e.printStackTrace();
            log.error("do operation log error:",e);
        }
    }


    public void addLogForUpdate(String moduleName, Serializable identityId, String operationName, String updateContent) {
        String updateContext2=getProperyI18N("operateLog", "lack for the operateLog key ",getCurrentOperatUser(), getDateStr(), moduleName, operationName, operationName, identityId, updateContent);
        addLogForUpdate(moduleName,updateContext2);
    }

    public abstract void addLogForUpdate(String moduleName,String updateContent) ;
//    {
//        try {
//            long currentTimeMillis = System.currentTimeMillis();
//            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//            String dateStr = sdf.format(new Date(currentTimeMillis));
//            Document document = new Document();
//            document.append("operator", ContextUtil.getCurrentUser())
//                    .append("from", "portal[javers]")
//                    .append("operate_time", currentTimeMillis)
//                    .append("module", moduleName).append("content", updateContent);
//            MongoUtil.insert("logs", new Document[]{document});
//        } catch (Exception e) {
//            log.info("保存日志异常", e);
//        }
//    }

    /**
     * resolve change list
     *
     * @param changes
     * @return the result with i18n
     */
    public String resolveChangeList(Object object,List<Change> changes){

        StringBuffer changeLog=new StringBuffer();
        if (changes!=null){
            changes.forEach(s->{
                if(s instanceof ValueChange){
                    ValueChange valueChange=(ValueChange)s;
                    String propertyName=valueChange.getPropertyName();
                    //常用 字段过滤
                    if (!getPropertyFilter().contains(propertyName)){
                        String FullName=new StringBuffer(object.getClass().getName()).append(".").append(propertyName).toString();
                        String propertyI18N=getProperyI18N(FullName,propertyName);
                        //国际化字段过滤
                        if (StringUtils.isNotEmpty(propertyI18N)){
                            try {
                                //如果有就获取父类的 没有则用本身的
                                Field field= object.getClass().getDeclaredField(propertyName);
                                UseValueI18N useValueI18N= field.getAnnotation(UseValueI18N.class);
                                if (useValueI18N!=null){
                                    String left=getProperyI18N(FullName+"."+valueChange.getLeft(),"");
                                    String right=getProperyI18N(FullName+"."+valueChange.getRight(),"");
                                    changeLog.append(getProperyI18N("fromtoChange", "", propertyI18N,left, right));
                                }else{
                                    UseEntityI18N useEntityI18N=field.getAnnotation(UseEntityI18N.class);
                                    if (useEntityI18N!=null){
                                        try{
                                            Object o =getFromDB(useEntityI18N.target(), (Serializable) valueChange.getLeft());
                                            String entityLeft=(String) PropertyUtils.getProperty(o,useEntityI18N.showProperty());
                                            o =getFromDB(useEntityI18N.target(), (Serializable) valueChange.getRight());
                                            String entityRight=(String) PropertyUtils.getProperty(o,useEntityI18N.showProperty());
                                            changeLog.append(getProperyI18N("fromtoChange", "", propertyI18N,entityLeft, entityRight));
                                        }catch (Exception e){
                                            log.info("failed to get data "+object.getClass()+" from dao class,detail:"+e);
                                        }
                                    }else{
                                        changeLog.append(getProperyI18N("fromtoChange", "", propertyI18N,valueChange.getLeft(), valueChange.getRight()));
                                    }
                                }
                            }catch (Exception e){
                                log.info("failed to get field from class "+object.getClass());
                            }
                        }
                    }
                }
            });
        }
        return changeLog.toString();
    }

    public String getDateStr(){
        long currentTimeMillis = System.currentTimeMillis();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(new Date(currentTimeMillis));
    }

    private String getProperyI18N(String key, String defaultVar, Object... params) {
        return i18NProcess.getProperyI18N(key,defaultVar,params);
    }
}

